package com.demo.mystudy.ui.socketclient

import android.util.Log
import com.demo.mystudy.socketbean.MessageWrapper
import com.demo.mystudy.socketbean.SimpleSocketBean
import com.demo.mystudy.ui.socketclient.clientcmd.ClientCmdDownloadFile
import com.demo.mystudy.ui.socketclient.clientcmd.ClientCmdInterface
import com.demo.mystudy.ui.socketclient.clientcmd.ClientCmdJetinnoFoler
import com.jetinno.simple.utils.JsonUtil
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.WebSocket
import okhttp3.WebSocketListener
import okio.ByteString

/**
 * Created by zhangyuncai on 2025/4/27.
 * 描述：
 */
object WebSocketClientManager {
    val mDatas = arrayListOf<String>()
    private var webSocket: WebSocket? = null
    var callback: SocketClientCallback? = null
    var isConnected: Boolean = false
    private val cmdMap: HashMap<String, ClientCmdInterface> by lazy {
        val list = mutableListOf<ClientCmdInterface>()
        list.add(ClientCmdJetinnoFoler)
        list.add(ClientCmdDownloadFile)
        val map = hashMapOf<String, ClientCmdInterface>()
        for (cmdInterface in list) {
            map[cmdInterface.cmd] = cmdInterface
        }
        map
    }

    fun connect(serverIp: String, port: Int) {
        val client = OkHttpClient()
        val request = Request.Builder()
            .url("ws://$serverIp:$port")
            .build()

        webSocket = client.newWebSocket(request, object : WebSocketListener() {

            override fun onOpen(webSocket: WebSocket, response: okhttp3.Response) {
                isConnected = true
                callback?.onConnectStausChanged(isConnected)
                Log.d("WebSocketClient", "连接成功")
                val simpleSocketBean = SimpleSocketBean()
                simpleSocketBean.content = "你好，我是客户端！"
                simpleSocketBean.cmd = "openClient"
                webSocket.send(JsonUtil.anyToJson(simpleSocketBean))
                addData("连接成功")
            }

            override fun onMessage(webSocket: WebSocket, text: String) {
                Log.d("WebSocketClient", "收到文本消息: $text")
                val messageWrapper =
                    JsonUtil.jsonToAny<MessageWrapper>(text, MessageWrapper::class.java)!!
                messageWrapper.message = text
                receiveMessage(messageWrapper)
                addData("收到文本消息: $text")
            }

            override fun onMessage(webSocket: WebSocket, bytes: ByteString) {
//                Log.d("WebSocketClient", "收到二进制消息: ${bytes.hex()}")
//                addData("收到二进制消息: ${bytes.hex()}")
                receiveBinaryMessage(bytes)
            }

            override fun onClosing(webSocket: WebSocket, code: Int, reason: String) {
                Log.d("WebSocketClient", "连接关闭中: $code $reason")
                webSocket.close(1000, null)
                addData("连接关闭中: $code $reason")
            }

            override fun onClosed(webSocket: WebSocket, code: Int, reason: String) {
                isConnected = false
                callback?.onConnectStausChanged(isConnected)
                Log.d("WebSocketClient", "连接已关闭: $code $reason")
                addData("连接已关闭: $code $reason")
            }

            override fun onFailure(
                webSocket: WebSocket,
                t: Throwable,
                response: okhttp3.Response?
            ) {
                Log.e("WebSocketClient", "连接失败: ${t.message}")
                addData("连接失败: ${t.message}")
            }
        })
    }

    fun sendMessage(message: String) {
        webSocket?.send(message)
    }

    fun close() {
        webSocket?.close(1000, "客户端主动断开")
    }

    internal fun addData(msg: String) {
        if (mDatas.size >= 10) {
            mDatas.removeAt(0)
        }
        mDatas.add(msg)
        callback?.addData(msg)
    }

    internal fun receiveMessage(messageWrapper: MessageWrapper) {
        val cmd = messageWrapper.cmd
        if (cmdMap.containsKey(cmd)) {
            val cmdInterface = cmdMap.get(cmd)!!
            cmdInterface.receive(messageWrapper)
        }
    }

    internal fun receiveBinaryMessage(bytes: ByteString) {
        ClientCmdDownloadFile.receiveBinary(bytes)
    }
}

interface SocketClientCallback {
    fun addData(msg: String)
    fun onConnectStausChanged(isConnected: Boolean)
}